#pragma once

#include <mysql_connection.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>

#include <queue>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <thread>

#include "const.h"
#include "data.h"


class SqlConnection{
public:
    SqlConnection(sql::Connection *con,int64_t lasttime):con_(std::unique_ptr<sql::Connection>(con)),lasttime_(lasttime){}
    ~SqlConnection()=default;
public:
    std::unique_ptr<sql::Connection> con_;
    int64_t lasttime_;
};


class MysqlPool
{
public:
    MysqlPool(std::size_t poolSize, std::string url, std::string user, std::string passwd, std::string schema)
    :poolSize_(poolSize)
    ,url_(url)
    ,user_(user)
    ,passwd_(passwd)
    ,schema_(schema)
    ,b_stop_(false)
    ,fail_count_(0)
    {
        for(int i = 0; i < poolSize_; ++i)
        {
            //1.获取数据库驱动
            sql::Driver* driver = get_driver_instance();
            if(!driver)
            {
                throw std::runtime_error("get_driver_instance failed");
            }
            //2.连接数据库

            sql::Connection * conn = driver->connect(url_,user_,passwd_);

            if (!conn)
            {
                std::cerr<<"connect failed"<<std::endl;
                throw std::runtime_error("connect failed");
            }
            std::cout<<"connect success"<<std::endl;
            conn->setSchema(schema_);
            // 获取当前时间戳
            auto currentTime = std::chrono::system_clock::now().time_since_epoch();
            // 将时间戳转换为秒
            long long timestamp = std::chrono::duration_cast<std::chrono::seconds>(currentTime).count();
            conns_.push(std::make_unique<SqlConnection>(conn,timestamp));
            
        }

        //启动保活线程
        check_thread_ = std::thread([this](){
            std::cout<<"check thread start"<<std::endl;
            while (!b_stop_)
            {
                //检查线程是否已经断开连接
                CheckConnection();
                //谁60s
                std::this_thread::sleep_for(std::chrono::seconds(10));
            }
            
        });

    }
    void CheckConnection()
    {
        // 1. 读取 目标处理数
        std::size_t targetCount;
        {
            std::lock_guard<std::mutex> lock(mtx_);
            targetCount = conns_.size();
        }

        // 2. 当前已经处理的数量
        std::size_t processed = 0;

        // 3. 时间戳
		auto now = std::chrono::system_clock::now().time_since_epoch();
		long long timestamp = std::chrono::duration_cast<std::chrono::seconds>(now).count();
        while (processed<targetCount)
        {
            std::unique_ptr<SqlConnection> con;
            {
                std::lock_guard<std::mutex> lock(mtx_);
                if(conns_.empty())
                {
                    break;
                }
                con= std::move(conns_.front());
                conns_.pop();

            }


            bool healthy = true;
            // 解锁后做检查/重连逻辑
            if (timestamp-con->lasttime_>=5)
            {
                // 做一个sql语句延长连接寿命
                try
                {
                    std::unique_ptr<sql::Statement> stmt(con->con_->createStatement());
                    stmt->executeQuery("SELECT 1");
                    // 更新时间戳
                    con->lasttime_ = timestamp;
                }
                catch(const sql::SQLException& e)
                {
                    std::cerr <<"check connection failed:"<< e.what() << '\n';
                    healthy = false;
                    fail_count_++;
                }
                
            }
            if (healthy)
            {
                // 如果健康，重新入队
                std::lock_guard<std::mutex> guard(mtx_);
				conns_.push(std::move(con));
				cond_.notify_one();
            }
            ++processed;
            
        }
        while (fail_count_>0)
        {
            auto b_res = reconnect(timestamp);
            if (b_res)
            {
                fail_count_--;
            }else
            {
                break;
            }
        }
        
        
    }
    // 重新建立一个连接
    bool reconnect(long long timestamp)
    {
        try
        {

            // 1.获取数据库驱动
        sql::Driver* driver = get_driver_instance();
        if(!driver)
        {
            throw std::runtime_error("get_driver_instance failed");
        }
        // 2.连接数据库
        sql::Connection * conn = driver->connect(url_,user_,passwd_);
        if (!conn)
        {
            std::cerr<<"connect failed"<<std::endl;
            throw std::runtime_error("connect failed");
        }
        std::cout<<"reconnect success"<<std::endl;
        // 3.设置要操作的数据库名称
        conn->setSchema(schema_);

        auto connPtr = std::make_unique<SqlConnection>(conn,timestamp);
        {
            std::lock_guard<std::mutex> lock(mtx_);
            conns_.push(std::move(connPtr));
        }
        return true;



        }
        catch(sql::SQLException& e)
        {
            std::cerr << e.what() << '\n';
            return false;
        }
        
    }
    // 获取一个连接
    std::unique_ptr<SqlConnection> GetConnection()
    {
    

        std::unique_lock<std::mutex> lock(mtx_);
        cond_.wait(lock, [this]() { return !conns_.empty()||b_stop_; });
        if (b_stop_)
        {
            return nullptr;
        }
        std::unique_ptr<SqlConnection> con = std::move(conns_.front());
        conns_.pop();

        return con;
    }
    // 归还一个连接
    void ReturnConnection(std::unique_ptr<SqlConnection> con)
    {
        std::lock_guard<std::mutex> lock(mtx_);
        if(b_stop_)
        {
            return;
        }
        conns_.push(std::move(con));
        cond_.notify_one();
    }

    void Close()
    {
        std::lock_guard<std::mutex> lock(mtx_);
        b_stop_ = true;
        cond_.notify_all();
        // 清空连接池
        while (!conns_.empty())
        {
            conns_.pop();
        }
        check_thread_.join();
    }
    ~MysqlPool()
    {
        Close();
    }
private:
    std::size_t poolSize_;
    std::string url_;
    std::string user_;
    std::string passwd_;
    std::string schema_;

    std::queue<std::unique_ptr<SqlConnection>> conns_;
    std::condition_variable cond_;
    std::mutex mtx_;
    bool b_stop_;
    // 保活机制，定时检查连接是否过期
    std::thread check_thread_;

    std::size_t fail_count_;
};

class MysqlDao
{
public:
    MysqlDao();
    ~MysqlDao();
    int RegUser(const std::string&name, const std::string& email, const std::string& pwd);
    // 到数据库中去查找用户名和邮箱是否匹配
    bool CheckEmail(const std::string& name, const std::string& email);
    // 更新密码
    bool UpdatePassword(const std::string& name, const std::string& pwd);
    // 检查密码和用户是否匹配
    bool CheckPwd(const std::string& name, const std::string& pwd,UserInfo& userinfo);
    
    // 根据uid查询用户信息
    std::shared_ptr<UserInfo> GetUser(int uid);
    // 根据用户名查询用户信息
    std::shared_ptr<UserInfo> GetUserByName(const std::string& name);

    // 添加好友申请记录
    bool AddFriendApply(int from_uid,int to_uid);

    // 获取好友申请列表
    bool GetApplyFriendList(int to_uid,std::vector<std::shared_ptr<ApplyInfo>>& apply_list,int offset,int limit=10);
private:
    std::unique_ptr<MysqlPool> pool_;


};